﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using System.Xml.XPath;
using Utilites;

namespace PhysEffects.HtmlParcer
{
    class TagKeeper
    {
        // TODO: класс для хранения распарсенных данных
        private HtmlDocument htmlDocument;

        public TagKeeper(String pageUrl)
        {
            HtmlWeb webPage = new HtmlWeb();
            htmlDocument = webPage.Load(pageUrl);
        }

        #region Public Functions

        public List<string> GetLinks()
        {
            return GetNodesAttribute("a", "href");
        }

        public string GetPageTitle()
        {
            return GetSingleNodeText("html/head/title");
        }

        public List<string> GetHeaders()
        {
            List<string> headers = new List<string>();
            List<string> tmpHeaders = new List<string>();
            
            for (int i = 1; i <= 6; i++)
            {
                string htmlNodeName = "//h" + i;

                tmpHeaders = GetNodesText(htmlNodeName);

                headers.AddRange(tmpHeaders);
            }

            return headers;
        }

        public List<string> GetBodyData()
        {
            HtmlNodeCollection bodyNodes;
            List<string> nodes = null;
            StringBuilder text = new StringBuilder();

            try
            {
                nodes = new List<string>();
                bodyNodes = htmlDocument.DocumentNode.SelectNodes("html/body//*");

                //IEnumerable<HtmlNode> dataNodes = GetBodyDataNodes(bodyNodes);
                IEnumerable<HtmlNode> dataNodes = bodyNodes.Where(Func);
                // TODO: проверить
                foreach (HtmlNode node in dataNodes)
                {
                    nodes.Add(node.InnerText);
                    text.Append(node.InnerText);
                }

                //Console.Write(text);
                Logger.WriteLog(text);
                int k = 0;
            }
            catch (Exception exception)
            {
                ExceptionManager.ProcessHtmlException(exception);
            }

            return nodes;
        }

        #endregion


        #region Private Functions

        private bool Func(HtmlNode node)
        {
            bool res = false;

            if (String.IsNullOrEmpty(node.InnerText) == false)
            {
                if (node.HasParent("header") == false && node.HasParent("footer") == false)
                {
                    if (node.Name.Equals("p") || node.HasParent("p"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("pre") || node.HasParent("pre"))
                    {
                        res = true;
                    }
                    if (node.IsHeaderNode() || node.HasParentHeaderNode())
                    {
                        res = true;
                    }
                    if (node.Name.Equals("ul") || node.HasParent("ul"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("dl") || node.HasParent("dl"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("em") || node.HasParent("em"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("ol") || node.HasParent("ol"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("table") || node.HasParent("table"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("a") || node.HasParent("a"))
                    {
                        res = true;
                    }
                    if (node.Name.Equals("div"))
                    {
                        res = true;
                    }
                }
                else
                {
                    res = false;
                }
            }            
            else
            {
                res = false;
            }

            return res;
        }

        private IEnumerable<HtmlNode> GetBodyDataNodes(HtmlNodeCollection nodeCollection)
        {
            return from node in nodeCollection
                   where
                    String.IsNullOrEmpty(node.InnerText) == false &&
                    (node.Name.Equals("p") || node.HasParent("p") ||
                    node.Name.Equals("pre") || node.HasParent("pre") ||
                    node.IsHeaderNode() || node.HasParentHeaderNode() ||
                    node.Name.Equals("ul") || node.HasParent("ul") ||
                    node.Name.Equals("ul") || node.HasParent("ul") ||
                    node.Name.Equals("div") || node.HasParent("div")) &&
                    (node.HasParent("header") == false && node.HasParent("footer") == false)
                   select node;
        }        

        private string GetSingleNodeText(string nodeXPath)
        {
            try
            {
                return htmlDocument.DocumentNode.SelectSingleNode(nodeXPath).InnerText;
            }
            catch (Exception exception)
            {
                ExceptionManager.ProcessHtmlException(exception);
            }

            return null;
        }

        private List<string> GetNodesText(string nodeXPath)
        {
            List<string> titles = null;

            try
            {
                titles = new List<string>();
                foreach (HtmlNode node in htmlDocument.DocumentNode.SelectNodes(nodeXPath))
                {
                    if (String.IsNullOrEmpty(node.InnerText) == false)
                    {
                        titles.Add(node.InnerText);
                    }
                }
            }
            catch (Exception exception)
            {
                ExceptionManager.ProcessHtmlException(exception);
            }

            return titles;
        }

        private List<string> GetNodesAttribute(string nodeXPath, string attributeXPath)
        {
            List<string> links = null;

            try
            {
                links = new List<string>();
                foreach (HtmlNode link 
                    in htmlDocument.DocumentNode.SelectNodes("//" + nodeXPath + "[@" + attributeXPath + "]"))
                {
                    HtmlAttribute att = link.Attributes[attributeXPath];

                    if (att != null)
                    {
                        links.Add(att.Value);
                    }
                }
            }
            catch (Exception exception)
            {
                ExceptionManager.ProcessHtmlException(exception);
            }

            return links;
        }

        #endregion
    }
}
